import datetime
import time
from random import Random
from rest_framework.filters import OrderingFilter
from users.models import Address, User
from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import status, mixins, viewsets
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import CreateAPIView, RetrieveAPIView, ListAPIView
from goods.models import Goods, GoodsAttribute, DiscountPackage
from .serializers import OrderSettlementSerializer, SaveOrderSerializer, Create_CouponSerializer, \
    GetcouponSerializer, GetordersSerializer, Get_Courier_CompanySerializer, LogisticsSerializer, GetReturnSerializer, \
    GoodsDetailSerializer, DiscountPackageSerializer, ReasonSerializer, OrderDiscountSerializer, PackageListSerializer
from orders.models import Courier_Company, DiscountCoupon, OrderGoods, ReturnDetail, ReturnDetailImage, \
    Business_Address, Reason
from orders.models import OrderInfo
from tasks import check_return


class OrderSettlementView(APIView):
    """购物车确认订单"""
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单

    def get(self, request):
        user = request.user
        # 从购物车中获取用户勾选要结算的商品信息
        redis_conn = get_redis_connection('cart')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        cart = {}
        for goods_id in cart_selected:  # 遍历出已勾选状态的商品id
            cart[int(goods_id)] = int(redis_cart[goods_id])  # 向空字典cart中添加键值对
        # 查询商品信息
        goods_list = GoodsAttribute.objects.filter(id__in=cart.keys())
        for goods in goods_list:
            goods.count = cart[goods.id]
            goods.weight = GoodsAttribute.objects.get(id=goods.id)
            goods.selected = True
        serializer = OrderSettlementSerializer({'Goods_list': goods_list}, context={'request': self.request}, )
        return Response(serializer.data)


class GetCourierCompanyView(RetrieveAPIView):
    """查询快递公司信息"""
    serializer_class = Get_Courier_CompanySerializer
    queryset = ''

    filter_backends = [OrderingFilter]
    ordering_fields = ('updata_time', 'create_time')
    lookup_field = 'status'

    def get(self, request, *args, **kwargs):
        queryset = Courier_Company.objects.all()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class SaveOrderView(CreateAPIView):
    """购物车生成订单"""
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    serializer_class = SaveOrderSerializer


"""下单处查询可用优惠券"""
class Order_CouponViewSet(ListAPIView):
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    queryset = DiscountCoupon.objects.filter(is_delete=False)
    serializer_class = OrderDiscountSerializer

    def get(self, request, *args, **kwargs):
        """适用于该商品列表的优惠券查询"""
        goods_list  =eval (request.query_params.get("goods_list"))
        # goods_list  =request.query_params.get("goods_list")
        queryset_goods =[]
        for goodsattribute in goods_list.values():
            obj = GoodsAttribute.objects.get(id = goodsattribute)
            goods_obj = Goods.objects.get(attribute =obj)
            queryset_2 = DiscountCoupon.objects.filter(user__isnull=True,category=2,goods_list__cate_goods = goods_obj)
            queryset_goods.extend(queryset_2)
        queryset_1 = DiscountCoupon.objects.filter(user__isnull=True,category=1)
        queryset_goods.extend(queryset_1)
        queryset_3 = DiscountCoupon.objects.filter(user=self.request.user,category= 3,status=False)
        queryset_goods.extend(queryset_3)
        queryset_goods = list(set(queryset_goods))
        """适用于该商品列表的优惠券查询"""
        queryset_old = DiscountCoupon.objects.filter(user=self.request.user, is_show=True,  # 正常领取的优惠券集合
                                                     status=False).exclude(category=3)
        queryset_cate3 = DiscountCoupon.objects.filter(category=3, user=self.request.user, status=False,
                                                       is_delete=False)
        queryset_user = []
        for obj in queryset_old:
            queryset_one = DiscountCoupon.objects.get(user__isnull=True, name=obj.name, is_delete=False)
            queryset_user.append(queryset_one)
        queryset_user.extend(queryset_cate3)
        queryset = list(set(queryset_goods).intersection(set(queryset_user)))
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class Order_Freight(APIView):
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    def get(self, request, *args, **kwargs):
        """适用于该商品列表的优惠券查询"""
        goods_list  =eval (request.query_params.get("goods_list"))
        if goods_list is None:
            return Response({"massage": "商品列表为空，无法判断快递费"})
        courier_company_id = request.query_params.get("courier_company")
        courier_company = Courier_Company.objects.get(id= courier_company_id)
        freight_list =[]
        for i in goods_list.values():
            goodsattribute = GoodsAttribute.objects.get(id = i)
            goods = Goods.objects.get(attribute=goodsattribute)
            if not goods.ship_free:  # 判断是否包邮
                freight_list.append(goodsattribute.weight * courier_company.price)
            else:
                freight_list.append(0)
        freight = min(freight_list)
        return  Response({'freight': freight})








class GoodsDetailOrderView(CreateAPIView):
    """
    商品详情页生成订单
    传参：goods_id,count,courier_company_id,address_id,pay_method_id, discount_coupon_id
    """
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    serializer_class = GoodsDetailSerializer


class DiscountPackageView(CreateAPIView):
    """
    套餐位置生成订单
    """
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    serializer_class = DiscountPackageSerializer


class PackageListView(ListAPIView):
    queryset = GoodsAttribute.objects.filter(is_delete=False)
    serializer_class = PackageListSerializer

    def list(self, request, *args, **kwargs):
        # 重写该方法，根据退换货类型返回原因
        goods_list = eval(request.query_params.get("goods_list"))
        queryset = []
        for goodsattribute in goods_list.values():
            obj = GoodsAttribute.objects.get(id = goodsattribute)
            queryset.append(obj)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class CouponView(CreateAPIView):
    """领取优惠券 post """
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    serializer_class = Create_CouponSerializer


class GetCouponsView(RetrieveAPIView):
    """查询优惠券列表 """
    serializer_class = GetcouponSerializer
    queryset = ''
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    filter_backends = [OrderingFilter]
    ordering_fields = ('updata_time', 'create_time',)
    lookup_field = 'status'

    def get(self, request, *args, **kwargs):
        status = int(self.kwargs.get("status"))
        if status == 2:  #  查询用户对象目前可使用的。
            queryset_old = DiscountCoupon.objects.filter(user=self.request.user, is_show=True,   # 正常领取的优惠券集合
                                                         status=False).exclude(category=3)
            queryset_cate3 = DiscountCoupon.objects.filter(category=3, user=self.request.user, status=False ,is_delete =False)
            queryset = []
            for obj in queryset_old:
                queryset_one = DiscountCoupon.objects.get(user__isnull=True, name=obj.name,is_delete= False)
                queryset.append(queryset_one)
            queryset.extend(queryset_cate3)
        elif status == 1:  # 查询当前可领取的
            queryset_1 = DiscountCoupon.objects.filter(user=self.request.user,).exclude(category=3) # 查询用户对象目前已领取。
            queryset_2 = DiscountCoupon.objects.filter(is_show=True, user=None,is_delete =False).exclude(category=3)  # 查询目前可以操作的所有优惠券模板。
            name = [k.name for k in queryset_1]
            queryset = []
            for i in queryset_2:
                if i.name not in name: queryset.append(i)
        else:
            queryset =None
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class GetordersView(RetrieveAPIView):
    """查询订单列表 """
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单
    serializer_class = GetordersSerializer
    queryset = ''
    filter_backends = [OrderingFilter]
    ordering_fields = ('updata_time', 'create_time')
    lookup_field = 'status'

    def get(self, request, *args, **kwargs):
        """查询用户所有订单"""
        status = self.kwargs.get("status")
        if status == 7:  # 查询该客户所有订单
            queryset = OrderInfo.objects.filter(user=self.request.user, is_show=True).order_by('-update_time')
        else:  # 查询该客户指定状态订单
            queryset = OrderInfo.objects.filter(status=status, user=self.request.user, is_show=True).order_by(
                '-update_time')
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def put(self, request):
        """逻辑删除客户订单"""
        order_id = request.data.get("order_id")
        order = OrderInfo.objects.get(user=self.request.user, order_id=order_id)
        order.is_show = False
        order.save()
        return Response({'message': '删除成功'})

    def post(self, request):
        """查询单个具体订单详情"""
        order_id = request.data.get("order_id")
        queryset = OrderInfo.objects.filter(user=self.request.user, is_show=True, order_id=order_id)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def delete(self, request):
        """未付款时，客户主动取消订单"""
        order_id = request.data.get("order_id")
        with transaction.atomic():  # 开启事务
            atomic_orders = transaction.savepoint()  # 创建保存点，记录当前数据状态
            try:
                order = OrderInfo.objects.get(order_id=order_id, user=self.request.user, status=1)
                ret_1 = OrderInfo.objects.filter(order_id=order_id, status=1).update(status=6,
                                                                                     is_show=False)  # 客户申请取消订单，将订单状态由待支付1更改为已取消6
                goods_list = OrderGoods.objects.filter(order=order)
                for order_goods in goods_list:
                    # 更改商品属性对象的库存
                    storage_amout = GoodsAttribute.objects.get(id=order_goods.goods.id).storage_amout
                    new_storage_amout = storage_amout + order_goods.count
                    ret_2 = GoodsAttribute.objects.filter(id=order_goods.goods.id).update(
                        storage_amout=new_storage_amout)  # 更新商品属性的库存
                    # 更改商品对象的销量
                    sold_num = Goods.objects.get(id=order_goods.goods.goods.id).sold_num
                    new_sold_num = sold_num - order_goods.count
                    ret_3 = Goods.objects.filter(id=order_goods.goods.goods.id).update(sold_num=new_sold_num)  # 更新商品销量
                # 如果该订单使用了优惠券，将优惠券数量变更回去，用户绑定的优惠券对象状态变更
                if order.discountcoupon:
                    ret_4 = DiscountCoupon.objects.filter(id=order.discountcoupon.id).update(status=False,
                                                                                             is_show=True)  # 更新客户绑定的优惠券
                    used_counts = DiscountCoupon.objects.get(name=order.discountcoupon.name, user=None).used_counts
                    new_used_counts = used_counts - 1
                    ret_5 = DiscountCoupon.objects.filter(name=order.discountcoupon.name, user=None,
                                                          used_counts=used_counts).update(
                        used_counts=new_used_counts)  # 更新该类型优惠券使用量
                if order.discountpackage:
                    new_number = order.discountpackage.number - 1
                    ret_6 = DiscountPackage.objects.filter(id=order.discountpackage.id).update(number=new_number)
                transaction.savepoint_commit(atomic_orders)  # 事物提交
                return Response({'message': '订单已取消'})
            except:
                transaction.savepoint_rollback(atomic_orders)  # 事物回滚
                return Response({'message': '参数有误'})


class GetReturnView(RetrieveAPIView):
    """查询退换货品列表 """
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单

    serializer_class = GetReturnSerializer
    queryset = ''

    filter_backends = [OrderingFilter]
    ordering_fields = ('updata_time', 'create_time')

    def get(self, request, *args, **kwargs):
        """查询退换货品列表"""
        queryset = ReturnDetail.objects.filter(user=self.request.user, is_show=True)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def put(self, request):
        """逻辑删除申请"""
        return_numbers = request.data.get("return_numbers")
        try:
            return_detail = ReturnDetail.objects.get(user=self.request.user, return_numbers=return_numbers)
        except:
            return Response({"massage": "退换货编号有误"})
        return_detail.is_show = False
        return_detail.save()
        return_detail.order_goods_id.is_return = 0
        return_detail.order_goods_id.save()
        return Response({'message': '删除成功'})


class LogisticsView(APIView):  # 退货时，输入快递单号
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行

    def post(self, request, ):
        """
        退换货时，携带退货编号return_numbers，以及要输入的快递单号numbers
        """
        serializer = LogisticsSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        return_numbers = serializer.validated_data.get('return_numbers')
        numbers = serializer.validated_data.get('numbers')
        company = serializer.validated_data.get('company')
        return_detail = ReturnDetail.objects.get(return_numbers=return_numbers)
        check_results = return_detail.check_results
        return_detail.numbers = numbers
        return_detail.company = company
        if check_results == 2:
            return_detail.check_results = 9
        elif check_results == 4:
            return_detail.check_results = 11
        elif check_results == 8:
            return_detail.check_results = 10
        else:
            return Response({"massage": "请求参数有误！"})
        return_detail.save()
        data = {
            "return_numbers": return_detail.return_numbers,
            "numbers": return_detail.numbers,
            "check_results": return_detail.check_results,
            "company": return_detail.company
        }
        return Response(data=data)

    def put(self, request, ):
        """用户登录状态下携带订单详情id，查询该订单退货地址。"""
        order_goods_id = request.data.get('id')
        ordergoods = OrderGoods.objects.get(id=order_goods_id)
        order_id = ordergoods.order.order_id
        orderinfo = OrderInfo.objects.get(order_id=order_id)
        business_address = orderinfo.business_address
        data = {
            "name": business_address.name,
            "person": business_address.person,
            "phone_number": business_address.phone_number,
            "province": business_address.province.name,
            "city": business_address.city.name,
            "district": business_address.district.name,
            "place": business_address.place
        }
        return Response(data=data)


class TakeGoods(APIView):
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行订单

    def post(self, request):
        """客户在收到货后主动点击签收按钮"""
        order_id = request.data.get('order_id')
        try:
            orderinfo = OrderInfo.objects.get(user=self.request.user, order_id=order_id)
        except:
            return Response({"massage": "订单号有误"})
        if orderinfo.status == 3:
            orderinfo.status = 5
            orderinfo.save()
            return Response({"massage": "收货成功"})
        else:
            return Response({"massage": "待收货状态下订单才能确认收货"})

    def put(self, request):
        """客户在待收货状态下，可以针对订单申请延长收货，携带个人身份信息，订单号order_id，延长时间over_time"""
        order_id = request.data.get('order_id')
        over_time = request.data.get('over_time')
        try:
            orderinfo = OrderInfo.objects.get(user=self.request.user, order_id=order_id)
        except:
            return Response({"massage": "订单号有误"})
        if over_time not in [3, 5, 7] or orderinfo.status != 3:
            return Response({"massage": "延长参数有误"})
        if orderinfo.over_time != 0:
            return Response({"massage": "该订单已经申请过延长时间"})
        orderinfo.over_time = over_time  # 数据库记录延长期限int
        delta = datetime.timedelta(days=orderinfo.over_time)  # 将延长期限转换为时间类型
        orderinfo.success_time = orderinfo.success_time + delta  # 默认交易成功时间增加延长期限
        orderinfo.save()
        data = {
            "order_id": order_id,
            "over_time": over_time,
            "success_time": orderinfo.success_time.strftime('%Y-%m-%d %H:%M:%S'),
        }
        return Response(data=data)


class GoodsReturnView(APIView):
    permission_classes = (IsAuthenticated,)  # 登录用户才能进行
    """
    退换货:user=self.request.user, is_show=True,
    只有在收到货的情况下进行退换操作
    """

    def put(self, request):
        id = request.data.get("id")
        introduce = request.data.get("introduce")
        is_return = request.data.get("is_return")
        reason_id = request.data.get("reason")
        image_list = request.data.get("image_list")
        user = request.user
        user_id = user.id
        return_id = request.data.get("return_id")
        return_address_id = request.data.get("return_address_id")
        ordergoods = OrderGoods.objects.get(id=id)
        order_id = ordergoods.order.order_id
        try:
            reason = Reason.objects.get(id=reason_id)
        except:
            return Response({'message': 'reason_id 传递有误！'})
        try:
            """ 查到该笔订单，如果不可退货，就不做更改"""
            order = OrderInfo.objects.get(user=self.request.user, order_id=order_id)
        except:
            return Response({'message': '订单商品有误!'})
        """更换的商品属性必须与下单时商品属性相同，且价格相同,才可申请更换"""
        if return_id:
            goods_new = GoodsAttribute.objects.get(id=return_id)  # 要更换的商品属性对象
            if (goods_new.goods.id != ordergoods.goods.goods.id) or \
                    (goods_new.price != ordergoods.goods.price):
                return Response({'message': '非同种商品不可更换,非价格相同不可更换'})
        """更换的收货地址关联用户必须与原用户相同"""
        if return_address_id:
            address_new = Address.objects.get(id=return_address_id)
            if (address_new.user != ordergoods.order.address.user) or \
                    (ordergoods.order.address.user != user):
                return Response({'message': '该地址不可使用'})
        random_ins = Random()
        return_numbers = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),
                                                             userid=user_id,
                                                             ranstr=random_ins.randint(10, 99))
        apply_time = datetime.datetime.now()
        with transaction.atomic():  # 开启事务
            save_id_return = transaction.savepoint()  # 记录事务节点
            """退换表单中创建一条数据"""
            try:
                returndetail = ReturnDetail.objects.create(
                    reason=reason,
                    order_goods_id=ordergoods,
                    introduce=introduce,
                    return_id=return_id,
                    return_address_id=return_address_id,
                    return_numbers=return_numbers,
                    apply_time=apply_time,
                    user=user
                )
                if image_list:
                    for image in image_list:
                        return_image = ReturnDetailImage.objects.create(
                            return_detail=returndetail,
                            image=image
                        )
                        return_image.save()
                if order.status == 3 and is_return == 1:  # 订单处于待收货状态,请求为退货
                    if ordergoods.order.discountcoupon:  # 如果退货订单包含优惠券，退款按照比例退款
                        discoupon_value = ordergoods.order.discountcoupon.value * (
                                    ordergoods.price * ordergoods.count / ordergoods.order.total_amount)
                    elif ordergoods.order.discountpackage:  # 套餐优惠退款金额处理
                        discoupon_value = ordergoods.order.discountpackage.saved_at_most * (
                                    ordergoods.price * ordergoods.count / ordergoods.order.total_amount)
                    else:
                        discoupon_value = 0
                    return_money = ordergoods.price * ordergoods.count - discoupon_value
                    returndetail.return_money = return_money
                    ordergoods.is_return = is_return
                elif order.status == 2 and is_return in [1, 3, 7]:  # 订单处于待发货状态,可申请退货，换货，仅退款
                    ordergoods.is_return = is_return
                else:
                    transaction.savepoint_rollback(save_id_return)
                    return Response({'message': '该请求不可操作!'})
                returndetail.save()
                ordergoods.save()
                check_return.delay(returndetail.id)
                transaction.savepoint_commit(save_id_return)
                return Response({'message': '状态变更成功!'})
            except Exception:
                transaction.savepoint_rollback(save_id_return)
                return Response({'message': '状态变更失败，请再次提交'})


class ReasonView(ListAPIView):
    """退换货原因"""
    queryset = Reason.objects.filter(is_enabled=True, is_delete=False)
    serializer_class = ReasonSerializer

    def list(self, request, *args, **kwargs):
        # 重写该方法，根据退换货类型返回原因
        return_type = request.query_params.get('return_type')
        queryset = self.filter_queryset(self.get_queryset())
        queryset = queryset.filter(return_type=return_type)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)






